package NW_Dynamic;

//import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

import NWPackage.Calculations;
import NWPackage.Cell;
import NWPackage.OneSettingDistMatrix;
import NWPackage.PairPreferdCandidateCell;
import NWPackage.PairPreferdCandidateMatrix;
import NWPackage.ProbabilitiesMatrix;
import NWPackage.Protocol;
import NWPackage.QueryFinderAlg;
import NWPackage.RankDist;
import NWPackage.WeightedEntropyMatrix;

public class Dynamic implements QueryFinderAlg {

	@Override
	public Cell FindNextQuery(ProbabilitiesMatrix probMatrix,PairPreferdCandidateMatrix pairsPreferredMatrix,List<String> optionalWinners, Protocol protocol) {
		
		double minEntropy = Double.POSITIVE_INFINITY; 
		Cell cell = null;

		//initial the weighted entropy matrix:
		WeightedEntropyMatrix entropyMatrix = new WeightedEntropyMatrix();
		entropyMatrix.initial();
		
		//for each "voter Pair preferred" (voter and Pair of Candidates) calculate the Weighted Entropy:
		// (i'm looping on PairPreferredMatrix in purpose because its contains only the relevant Cells)  
		
		for (int i = 0; i< pairsPreferredMatrix.getLength(); i++) {
			if (pairsPreferredMatrix.getCell(i).getPrefered_C() == null && pairsPreferredMatrix.getCell(i).isExistIn(optionalWinners)){
				double weightedEntropy = CalcWeightedEntropy(pairsPreferredMatrix.getCell(i),probMatrix,optionalWinners);
				//insert the Weighted Entropy into the Entropy Matrix
				entropyMatrix.setEntropyInCell(i,weightedEntropy);
				
				if (weightedEntropy < minEntropy)
				{
					minEntropy = weightedEntropy;
					cell = pairsPreferredMatrix.getCell(i);
				}
			}
		}
		
		//Return Query (as Cell) with the lowest Entropy, Return NULL if no Query found
		return cell;
	}

	private double CalcWeightedEntropy(PairPreferdCandidateCell cell, ProbabilitiesMatrix probMatrix, List<String> optionalWinners) {
		//create two Assumptions cells (A>B and A<B)
		String[] candidates = cell.getCandidates();
		PairPreferdCandidateCell bigCellAssumption = new PairPreferdCandidateCell(cell.getAgentName(),candidates[0],candidates[1], candidates[0]);
		PairPreferdCandidateCell smallCellAssumption = new PairPreferdCandidateCell(cell.getAgentName(),candidates[0],candidates[1], candidates[1]);
		
		//make temp Normalize probability Matrix for each Assumption:
		ProbabilitiesMatrix bigNormalizeProbabilityMatrix = probMatrix.normalize(bigCellAssumption);
		ProbabilitiesMatrix smallNormalizeProbabilityMatrix = probMatrix.normalize(smallCellAssumption);
		
		//initial statistics
		double[] weight1;
		double[] weight2;
		
		//calc twice for A<B and A>B Assumptions the Weighted Entropy:
		weight1 = CalcAssumptionEntropy(bigNormalizeProbabilityMatrix,bigCellAssumption,optionalWinners);
		weight2 = CalcAssumptionEntropy(smallNormalizeProbabilityMatrix,smallCellAssumption,optionalWinners);
		
		double sumWeight1 = Calculations.Sum(weight1);
		double sumWeight2 = Calculations.Sum(weight2);
		
		//we can change the return calculations!
		return sumWeight1*bigNormalizeProbabilityMatrix.getAgentTotalProbability(bigCellAssumption.getAgentName()) + sumWeight2*smallNormalizeProbabilityMatrix.getAgentTotalProbability(smallCellAssumption.getAgentName());
	}


	private double[] CalcAssumptionEntropy(ProbabilitiesMatrix normalizeProbabilityMatrix, PairPreferdCandidateCell cellAssumption, List<String> optionalWinners) {
		
		double[] ansWeights = new double[2];
		
		//build dist. matrix with one setting explored:
		OneSettingDistMatrix osdm = new OneSettingDistMatrix();
		osdm.importProbabilitiesMatrix(normalizeProbabilityMatrix);
		
		OneSettingDistMatrix osdmTempIteration = new OneSettingDistMatrix();
		osdmTempIteration.importProbabilitiesMatrix(normalizeProbabilityMatrix);
		
		OneSettingDistMatrix osdmTemp2Iteration = new OneSettingDistMatrix();
		osdmTemp2Iteration.importProbabilitiesMatrix(normalizeProbabilityMatrix);
		
		//in each round/iteration we need to check each posibility for Voter/Cand/Vote
		//this will be calc for the same Voter twice! for C1 & C2 (taken from cellAssumption)
		String[] candidates  = cellAssumption.getCandidates();
		
		RankDist cand1List = CalcWeightedEntropyList(cellAssumption.getAgentName(),candidates[0],osdmTempIteration,optionalWinners);
		RankDist cand2List = CalcWeightedEntropyList(cellAssumption.getAgentName(),candidates[1],osdmTemp2Iteration,optionalWinners);
		
		ansWeights[0] = cand1List.calcSumWeightedWithOSDM(osdm,cellAssumption.getAgentName(),candidates[0]);
		ansWeights[1] = cand2List.calcSumWeightedWithOSDM(osdm,cellAssumption.getAgentName(),candidates[1]);
		
		return ansWeights;
	}

	private RankDist CalcWeightedEntropyList(String agent,String candidate, OneSettingDistMatrix osdmTempIteration, List<String> optionalWinners) {
		int numOfVotes = osdmTempIteration.getNumberOfVotes(agent,candidate);
		RankDist weightedEntropyList = new RankDist();
		
		for (int i = 1; i <= numOfVotes; i++) {
			weightedEntropyList.addRank(i, CalcWeightedEntropy(agent,candidate,i,osdmTempIteration,optionalWinners));
		}
		return weightedEntropyList;
	}

	private double CalcWeightedEntropy(String agent, String candidate, int voteCheck, OneSettingDistMatrix osdmTempIteration, List<String> optionalWinners) {
		int numberOfVotes = osdmTempIteration.getNumberOfVotes(agent, candidate);
		Set<String> voters = osdmTempIteration.getVoters();
		
		//1. place 1 where Rank = i and 0 elsewhere
		osdmTempIteration.fixRank(agent,candidate,voteCheck);
		
		//2. for each optional-winner-candidate calc the Probability that Cand-x = s
		HashMap<String, RankDist> allProbsEqual= new HashMap<String, RankDist>();
		//for each vote calc the probability (step 1 in excel)
		DynamicHelper.CalcCandidateVoteProbability(osdmTempIteration, optionalWinners, numberOfVotes, voters, allProbsEqual);
		
		//3. for each candidate calc the Probability that Cand-x = at most s
		HashMap<String,RankDist> allProbsMost = new HashMap<String, RankDist>();
		DynamicHelper.CalcCandidateVoteCumulative(allProbsMost,allProbsEqual, numberOfVotes, voters);
		
		//4. for each candidate calc the Probability that Cand-x = s is winner
		HashMap<String,RankDist> allProbsIsWinner = new HashMap<String, RankDist>();
		DynamicHelper.CalcCandidateProbForWinning(allProbsIsWinner,allProbsMost,allProbsEqual,numberOfVotes, voters ,optionalWinners);
		
		//5. calc sum of all the Entropies of all the Candidates
		double weightedEntropy = DynamicHelper.CalcEntropyOfVectors(allProbsIsWinner);
		
		
		return weightedEntropy;
	}
	
	

	
}
